#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/9/17 15:24
# @Author  : youfeng
import time

from config.redis_conf import RedisDataCacheConfig, RedisScheduleCacheConfig
from enum.crawl_expire_time import CrawlExpireTime
from enum.data_status import DataStatus
from etl.data_etl import DataETL
from etl.etl_wrap import ETLWrap
from ext.mongo_handler import MongoHandler
from ext.mq_handler import MQHandler
from ext.redis_result_handler import RedisResultHandler
from ext.redis_schedule_handler import RedisScheduleHandler


class DataHandler(object):

    def __init__(self, log):
        self.log = log
        # redis 结果 访问句柄
        self.__redis_result_handler = RedisResultHandler(RedisDataCacheConfig.HOST,
                                                         RedisDataCacheConfig.PORT,
                                                         RedisDataCacheConfig.PASSWORD,
                                                         RedisDataCacheConfig.DB,
                                                         RedisDataCacheConfig.MAX_CONNECTIONS, log)

        # redis 调度缓存访问句柄
        self.__redis_schedule_handler = RedisScheduleHandler(RedisScheduleCacheConfig.HOST,
                                                             RedisScheduleCacheConfig.PORT,
                                                             RedisScheduleCacheConfig.PASSWORD,
                                                             RedisScheduleCacheConfig.DB,
                                                             RedisScheduleCacheConfig.MAX_CONNECTIONS)

        # mongodb 访问句柄
        self.__mongo_handler = MongoHandler(log)

        # 调度句柄, 负责发送企业名单到下游 负责发送周期调度数据到下游
        self.__mq_handler = MQHandler(log)

        # ETL 句柄
        self.__etl_handler = DataETL(log)

        self.log.info("数据操作句柄初始化完成...")

    def __wait(self, company, func, timeout):
        if timeout <= 0:
            timeout = 15

        self.log.info("等待采集结果: company = {} func = {}".format(company, func))
        for _ in xrange(timeout):
            result = func(company)
            if isinstance(result, dict):
                return result

            # 解析错误
            if result == -1:
                return None

            time.sleep(1)

        return None

    # 工商数据接口
    def get_gsxt_data(self, company):
        is_schedule_cache = False
        result = self.__redis_result_handler.get_gsxt_result(company)
        if isinstance(result, dict):
            self.log.info("从redis中获取工商数据成功: company = {}".format(company))
            return DataStatus.SUCCESS, self.__etl_handler.get_gsxt_data(result)

        try:
            # 这里要判断是否已经在调度了，如果在调度则不发送消息队列直接等待数据
            if not self.__redis_schedule_handler.is_gsxt_schedule(company):

                # 判断 消息队列是否满了
                if self.__mq_handler.is_gsxt_block():
                    return DataStatus.BUSY, None

                if not self.__mq_handler.send_gsxt_request(company):
                    self.log.error("发送工商采集消息队列异常: company = {}".format(company))
                    return DataStatus.FAIL, None

                self.__redis_schedule_handler.add_to_gsxt_schedule(company)
                is_schedule_cache = True

            result = self.__wait(company, self.__redis_result_handler.get_gsxt_result,
                                 CrawlExpireTime.MAX_GSXT_EXPIRE_TIME)
            if isinstance(result, dict):
                self.log.info("采集工商数据成功: company = {}".format(company))
                return DataStatus.SUCCESS, self.__etl_handler.get_gsxt_data(result)

            self.log.info("工商未采集完成，从mongo中提取数据: company = {}".format(company))
            db_result = self.__mongo_handler.get_gsxt_data(company)
            if db_result is None:
                self.log.warn("MongoDB 没有搜索到任何工商结果: company = {}".format(company))
                return DataStatus.NOT_FOUND, None
        finally:
            if is_schedule_cache:
                self.__redis_schedule_handler.del_gsxt_schedule(company)

        return DataStatus.SUCCESS, self.__etl_handler.get_gsxt_data(ETLWrap.result_wrap([db_result]))

    # 文书数据接口
    def get_wenshu_data(self, company):
        is_schedule_cache = False
        result = self.__redis_result_handler.get_wenshu_result(company)
        if isinstance(result, dict):
            self.log.info("从redis中获取文书数据成功: company = {}".format(company))
            return DataStatus.SUCCESS, self.__etl_handler.get_wenshu_data(result)

        try:
            # 这里要判断是否已经在调度了，如果在调度则不发送消息队列直接等待数据
            if not self.__redis_schedule_handler.is_wenshu_schedule(company):
                # 判断 消息队列是否满了
                if self.__mq_handler.is_wenshu_block():
                    return DataStatus.BUSY, None

                if not self.__mq_handler.send_wenshu_request(company):
                    self.log.error("发送裁判文书采集消息队列异常: company = {}".format(company))
                    return DataStatus.FAIL, None
                self.__redis_schedule_handler.add_to_wenshu_schedule(company)
                is_schedule_cache = True

            result = self.__wait(company, self.__redis_result_handler.get_wenshu_result,
                                 CrawlExpireTime.MAX_WENSHU_EXPIRE_TIME)
            if isinstance(result, dict):
                self.log.info("采集文书数据成功: company = {}".format(company))
                return DataStatus.SUCCESS, self.__etl_handler.get_wenshu_data(result)

            self.log.info("文书未采集完成，从mongo中提取数据: company = {}".format(company))
            db_result_list = self.__mongo_handler.get_wenshu_summary(company)
            if db_result_list is None:
                self.log.warn("MongoDB 搜索文书结果异常: company = {}".format(company))
                return DataStatus.FAIL, None
        finally:
            if is_schedule_cache:
                self.__redis_schedule_handler.del_wenshu_schedule(company)

        return DataStatus.SUCCESS, self.__etl_handler.get_wenshu_data(ETLWrap.result_wrap(db_result_list))

    # 新闻数据接口
    def get_news_data(self, company):
        is_schedule_cache = False
        result = self.__redis_result_handler.get_news_result(company)
        if isinstance(result, dict):
            self.log.info("从redis中获取新闻数据成功: company = {}".format(company))
            return DataStatus.SUCCESS, self.__etl_handler.get_news_data(result)

        try:
            # 这里要判断是否已经在调度了，如果在调度则不发送消息队列直接等待数据
            if not self.__redis_schedule_handler.is_news_schedule(company):
                # 判断 消息队列是否满了
                if self.__mq_handler.is_news_block():
                    return DataStatus.BUSY, None

                if not self.__mq_handler.send_news_request(company):
                    self.log.error("发送新闻采集消息队列异常: company = {}".format(company))
                    return DataStatus.FAIL, None
                self.__redis_schedule_handler.add_to_news_schedule(company)
                is_schedule_cache = True

            result = self.__wait(company, self.__redis_result_handler.get_news_result,
                                 CrawlExpireTime.MAX_NEWS_EXPIRE_TIME)
            if isinstance(result, dict):
                self.log.info("采集新闻数据成功: company = {}".format(company))
                return DataStatus.SUCCESS, self.__etl_handler.get_news_data(result)

            self.log.info("新闻未采集完成，从mongo中提取数据: company = {}".format(company))
            db_result_list = self.__mongo_handler.get_news_data(company)
            if db_result_list is None:
                self.log.warn("MongoDB 搜索新闻结果异常: company = {}".format(company))
                return DataStatus.FAIL, None
        finally:
            if is_schedule_cache:
                self.__redis_schedule_handler.del_news_schedule(company)

        return DataStatus.SUCCESS, self.__etl_handler.get_news_data(ETLWrap.result_wrap(db_result_list))

    # 执行数据接口
    def get_zhixing_data(self, company):
        is_schedule_cache = False
        result = self.__redis_result_handler.get_zhixing_result(company)
        if isinstance(result, dict):
            self.log.info("从redis中获取执行数据成功: company = {}".format(company))
            return DataStatus.SUCCESS, self.__etl_handler.get_zhixing_data(result)

        try:
            # 这里要判断是否已经在调度了，如果在调度则不发送消息队列直接等待数据
            if not self.__redis_schedule_handler.is_zhixing_schedule(company):
                # 判断 消息队列是否满了
                if self.__mq_handler.is_zhixing_block():
                    return DataStatus.BUSY, None

                if not self.__mq_handler.send_zhixing_request(company):
                    self.log.error("发送执行采集消息队列异常: company = {}".format(company))
                    return DataStatus.FAIL, None
                self.__redis_schedule_handler.add_to_zhixing_schedule(company)
                is_schedule_cache = True

            result = self.__wait(company, self.__redis_result_handler.get_zhixing_result,
                                 CrawlExpireTime.MAX_ZHIXING_EXPIRE_TIME)
            if isinstance(result, dict):
                self.log.info("采集执行数据成功: company = {}".format(company))
                return DataStatus.SUCCESS, self.__etl_handler.get_zhixing_data(result)

            self.log.info("执行未采集完成，从mongo中提取数据: company = {}".format(company))
            db_result_list = self.__mongo_handler.get_zhixing_data(company)
            if db_result_list is None:
                self.log.warn("MongoDB 搜索执行结果异常: company = {}".format(company))
                return DataStatus.FAIL, None
        finally:
            if is_schedule_cache:
                self.__redis_schedule_handler.del_zhixing_schedule(company)

        return DataStatus.SUCCESS, self.__etl_handler.get_zhixing_data(ETLWrap.result_wrap(db_result_list))

    # 失信数据接口
    def get_shixin_data(self, company):
        is_schedule_cache = False
        result = self.__redis_result_handler.get_shixin_result(company)
        if isinstance(result, dict):
            self.log.info("从redis中获取失信数据成功: company = {}".format(company))
            return DataStatus.SUCCESS, self.__etl_handler.get_shixin_data(result)

        try:
            # 这里要判断是否已经在调度了，如果在调度则不发送消息队列直接等待数据
            if not self.__redis_schedule_handler.is_shixin_schedule(company):
                # 判断 消息队列是否满了
                if self.__mq_handler.is_shixin_block():
                    return DataStatus.BUSY, None

                if not self.__mq_handler.send_shixin_request(company):
                    self.log.error("发送失信采集消息队列异常: company = {}".format(company))
                    return DataStatus.FAIL, None
                self.__redis_schedule_handler.add_to_shixin_schedule(company)
                is_schedule_cache = True

            result = self.__wait(company, self.__redis_result_handler.get_shixin_result,
                                 CrawlExpireTime.MAX_SHIXIN_EXPIRE_TIME)
            if isinstance(result, dict):
                self.log.info("采集失信数据成功: company = {}".format(company))
                return DataStatus.SUCCESS, self.__etl_handler.get_shixin_data(result)

            self.log.info("失信未采集完成，从mongo中提取数据: company = {}".format(company))
            db_result_list = self.__mongo_handler.get_shixin_data(company)
            if db_result_list is None:
                self.log.warn("MongoDB 搜索失信结果异常: company = {}".format(company))
                return DataStatus.FAIL, None
        finally:
            if is_schedule_cache:
                self.__redis_schedule_handler.del_shixin_schedule(company)

        return DataStatus.SUCCESS, self.__etl_handler.get_shixin_data(ETLWrap.result_wrap(db_result_list))
